package com.huayun.plugin.bk.controller;

import com.huayun.plugin.bk.service.AirfoilVisualizer;
import com.huayun.plugin.bk.service.XfoilEmbedded;
import javafx.application.Platform;
import javafx.embed.swing.JFXPanel;
import javafx.stage.Stage;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.InputStreamResource;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.nio.file.Files;
import java.util.List;
import java.util.Map;
import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;

@RestController
@RequestMapping("/bk")
@RequiredArgsConstructor
public class FileController {
    @Autowired
    private XfoilEmbedded xfoilEmbedded;


    /**
     * 上传并解析 .dat 文件的方法。
     * 该方法接收一个 .dat 文件作为输入，调用 XfoilEmbedded 服务运行 XFOIL 分析，并生成压力分布图。
     *
     * @param file         待上传的 .dat 文件
     * @param visc         黏性系数，用于 XFOIL 分析
     * @param startAngle   起始攻角，用于 XFOIL 分析
     * @param endAngle     结束攻角，用于 XFOIL 分析
     * @param stepAngle    攻角步长，用于 XFOIL 分析
     * @return 如果文件上传和分析成功，返回 HTTP 响应，包含成功消息；
     *         如果文件为空或分析失败，返回相应的错误信息。
     */
    @RequestMapping(value = "/uploadDat", method = RequestMethod.POST)
    public ResponseEntity<String> uploadDatFile(@RequestParam("file") MultipartFile file, @RequestParam("visc") double visc,
                                               @RequestParam("startAngle") double startAngle, @RequestParam("endAngle") double endAngle, @RequestParam("stepAngle") double stepAngle) {
        if (file.isEmpty()) {
            return ResponseEntity.badRequest().body(null);
        }
        String workDir = System.getProperty("user.dir") + File.separator + "xfoil";
        try {
            // 创建工作目录（如果不存在）
            Files.createDirectories(Paths.get(workDir));
            // 构建目标文件路径
            Path targetPath = Paths.get(workDir, file.getOriginalFilename());
            // 将上传的文件保存到目标路径
            Files.copy(file.getInputStream(), targetPath, java.nio.file.StandardCopyOption.REPLACE_EXISTING);

            xfoilEmbedded.run(file.getOriginalFilename(), visc, startAngle, endAngle, stepAngle);

            // 初始化JavaFX平台
            new JFXPanel(); // 这行代码用于初始化JavaFX平台

            // 创建并启动AirfoilVisualizer
            Platform.runLater(() -> {
                try {
                    AirfoilVisualizer visualizer = new AirfoilVisualizer();
                    visualizer.start(new Stage());
                } catch (Exception e) {
                    e.printStackTrace();
                }
            });

            return ResponseEntity.ok("上传成功");
        } catch (IOException e) {
            e.printStackTrace();
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(null);
        }
    }


    /**
     * 导出 XFOIL 分析结果文件的方法。
     * 该方法将 XFOIL 分析生成的极坐标文件 (polar.txt)、压力系数图片 (cp.png)、极坐标图 (plot.ps) 和标准输出文件 (outPut.txt) 打包成 ZIP 文件，并通过 HTTP 响应返回给客户端。
     *
     * @param visc 黏性系数，用于 XFOIL 分析
     * @return 如果文件导出成功，返回 HTTP 响应，包含生成的 ZIP 文件流；
     *         如果某些文件不存在，返回 404 错误响应。
     * @throws IOException 如果在文件操作过程中发生 IO 错误。
     */
    @RequestMapping(value = "/exportDatFile", method = RequestMethod.POST)
    public ResponseEntity<Resource> exportDatFile(@RequestParam("visc") double visc) throws IOException {

        String workDir = System.getProperty("user.dir") + File.separator + "xfoil";

        String polarFilePath = XfoilEmbedded.getPolarFilePath();
        File polarFile = new File(polarFilePath);

        String plotPsPath = workDir + File.separator + "plot.ps";
        File plotFile = new File(plotPsPath);

        String cpPhotoFilePath = workDir + File.separator + "cp.png";
        File cpPhotoFile = new File(cpPhotoFilePath);

        String outPutFilePath = workDir + File.separator + "outPut.txt";
        File outPutFile = new File(outPutFilePath);



        // 检查文件是否存在
        if (!polarFile.exists() ) {
            return ResponseEntity.status(HttpStatus.NOT_FOUND).body(null);
        }

        if (!cpPhotoFile.exists()) {
            return ResponseEntity.status(HttpStatus.NOT_FOUND).body(null); // 如果超时未生成 cp.png，返回错误
        }
        if (!plotFile.exists() ) {
            return ResponseEntity.status(HttpStatus.NOT_FOUND).body(null);
        }

        if (!outPutFile.exists() ) {
            return ResponseEntity.status(HttpStatus.NOT_FOUND).body(null);
        }

        // 将两个文件打包成 ZIP
        ByteArrayOutputStream zipOutputStream = new ByteArrayOutputStream();
        ZipOutputStream zos = new ZipOutputStream(zipOutputStream);

        addFileToZip(zos, polarFile, "polar.txt");
        addFileToZip(zos, cpPhotoFile, "cp.png");
        addFileToZip(zos, plotFile, "plot.ps");
        addFileToZip(zos, outPutFile, "outPut.txt");
        zos.close();
        zipOutputStream.close();

        // 返回 ZIP 文件
        InputStreamResource resource = new InputStreamResource(new ByteArrayInputStream(zipOutputStream.toByteArray()));
        return ResponseEntity.ok()
                .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=results.zip")
                .contentType(MediaType.APPLICATION_OCTET_STREAM)
                .body(resource);
    }

    /**
     * 将文件添加到 ZIP 输出流中。
     * 该方法用于将指定的文件以指定的条目名称写入 ZIP 输出流。
     *
     * @param zos       ZIP 输出流对象
     * @param file      要添加到 ZIP 文件中的文件对象
     * @param entryName ZIP 文件中的条目名称
     * @throws IOException 如果在文件操作过程中发生 IO 错误
     */
    private void addFileToZip(ZipOutputStream zos, File file, String entryName) throws IOException {
        ZipEntry zipEntry = new ZipEntry(entryName);
        zos.putNextEntry(zipEntry);
        Files.copy(file.toPath(), zos);
        zos.closeEntry();
    }

}